﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Input;
using Pavilion;

namespace Pavilion.Control
{
    public class InputComponent
    {
        #region //////////////////////////////////////Attributes and Constructor//////////////////////////////////////

        private Control control;
        private DateTime doubleClickTime;
        private bool isInside;

        public event Action<Keys[]> KeyPressed, KeyReleased;
        public event EventHandler Enter, Leave;
        public event MouseObjectHandler MousePress, MouseMoved;
        public event MouseObjectHandler MouseRelease;
        public event Action<MouseCursor> OuterClick, DoubleClick;

        public InputComponent(Control control)
        {
            this.control = control;
            doubleClickTime = DateTime.Now;

            control.IsActiveChanged += new Action<bool>(Control_IsActiveChanged);

            LoadMouse();
            LoadKeyboard();
            LoadOuterClick();
        }

        public void Dispose()
        {
            control.IsActiveChanged -= new Action<bool>(Control_IsActiveChanged);

            UnloadMouse();
            UnloadKeyboard();
            UnloadOuterClick();
        }

        #endregion

        #region ///////////////////////////////////////////////Methods////////////////////////////////////////////////

        private void LoadMouse()
        {
            if (isInside)
            {
                RootControl.Instance.MouseCursor.LeftMousePressed += new Action<MouseCursor>(MouseCursor_LeftMousePressed);
                RootControl.Instance.MouseCursor.RightButtonPressed += new Action<MouseCursor>(MouseCursor_RightButtonPressed);
                RootControl.Instance.MouseCursor.LeftMouseReleased += new Action<MouseCursor>(MouseCursor_LeftMouseReleased);
                RootControl.Instance.MouseCursor.RightButtonReleased += new Action<MouseCursor>(MouseCursor_RightButtonReleased);
                RootControl.Instance.MouseCursor.MouseMoved += new Action<MouseCursor>(MouseCursor_MouseMoved);
            }
        }

        private void UnloadMouse()
        {
            if (!isInside)
            {
                RootControl.Instance.MouseCursor.LeftMousePressed -= new Action<MouseCursor>(MouseCursor_LeftMousePressed);
                RootControl.Instance.MouseCursor.RightButtonPressed -= new Action<MouseCursor>(MouseCursor_RightButtonPressed);
                RootControl.Instance.MouseCursor.LeftMouseReleased -= new Action<MouseCursor>(MouseCursor_LeftMouseReleased);
                RootControl.Instance.MouseCursor.RightButtonReleased -= new Action<MouseCursor>(MouseCursor_RightButtonReleased);
                RootControl.Instance.MouseCursor.MouseMoved -= new Action<MouseCursor>(MouseCursor_MouseMoved);
            }
        }

        private void LoadOuterClick()
        {
            if (control.IsActive)
            {
                RootControl.Instance.MouseCursor.LeftMousePressed += new Action<MouseCursor>(MouseCursor_LeftMousePressedOutside);
                RootControl.Instance.MouseCursor.RightButtonPressed += new Action<MouseCursor>(MouseCursor_RightButtonPressedOutside);
            }
        }

        private void UnloadOuterClick()
        {
            if (!control.IsActive)
            {
                RootControl.Instance.MouseCursor.LeftMousePressed -= new Action<MouseCursor>(MouseCursor_LeftMousePressedOutside);
                RootControl.Instance.MouseCursor.RightButtonPressed -= new Action<MouseCursor>(MouseCursor_RightButtonPressedOutside);
            }
        }

        private void LoadKeyboard()
        {
            if (control.IsActive)
            {
                RootControl.Instance.Keyboard.KeysPressed += new Action<Keys[]>(PlayerKeyboard_KeysPressed);
                RootControl.Instance.Keyboard.KeysReleased += new Action<Keys[]>(PlayerKeyboard_KeysReleased);
            }
        }

        private void UnloadKeyboard()
        {
            if (!control.IsActive)
            {
                RootControl.Instance.Keyboard.KeysPressed -= new Action<Keys[]>(PlayerKeyboard_KeysPressed);
                RootControl.Instance.Keyboard.KeysReleased -= new Action<Keys[]>(PlayerKeyboard_KeysReleased);
            }
        }

        #endregion

        #region ////////////////////////////////////////General Gets and Sets/////////////////////////////////////////

        /// <summary>
        /// Gets the sets whether the mouse is inside the control.
        /// </summary>
        private bool IsInside
        {
            get { return isInside; }
            set
            {
                if (isInside == value)
                    return;

                isInside = value;

                if (isInside)
                {
                    LoadMouse();

                    if (Enter != null)
                        Enter(this, EventArgs.Empty);
                }
                else
                {
                    UnloadMouse();

                    if (Leave != null)
                        Leave(this, EventArgs.Empty);
                }
            }
        }

        #endregion

        #region ////////////////////////////////////////////////Events////////////////////////////////////////////////

        public virtual void OnEnter()
        {
            if (IsInside)
                return;

            IsInside = true;
        }

        public virtual void OnLeave()
        {
            if (!IsInside)
                return;

            IsInside = false;
        }

        private void OnMouseMoved(MouseCursor mouseCursor)
        {
            if (MouseMoved != null)
                MouseMoved(control, mouseCursor);
        }

        private void OnOuterClick(MouseCursor mouseCursor)
        {
            if (OuterClick != null && !mouseCursor.checkBounds(control.ScreenBounds))
                OuterClick(mouseCursor);
        }

        private void OnDoubleClick(MouseCursor mouseCursor)
        {
            if (DoubleClick != null)
                DoubleClick(mouseCursor);
        }

        private void OnMousePress(MouseCursor mouseCursor)
        {
            if (MousePress != null)
                MousePress(control, mouseCursor);

            if (DoubleClick != null)
            {
                TimeSpan timeDifference = DateTime.Now - doubleClickTime;
                doubleClickTime = DateTime.Now;
                if (timeDifference.TotalSeconds < 0.3f)
                    OnDoubleClick(mouseCursor);
            }
        }

        private void OnMouseRelease(MouseCursor mouseCursor)
        {
            if (MouseRelease != null)
                MouseRelease(control, mouseCursor);
        }

        private void OnKeyPressed(Keys[] keys)
        {
            if (KeyPressed != null)
                KeyPressed(keys);
        }

        private void OnKeyReleased(Keys[] keys)
        {
            if (KeyReleased != null)
                KeyReleased(keys);
        }

        private void Control_IsActiveChanged(bool isActive)
        {
            if (isActive)
            {
                LoadKeyboard();
                LoadOuterClick();
            }
            else
            {
                UnloadKeyboard();
                UnloadOuterClick();

                if (IsInside)
                    IsInside = false;
            }
        }

        private void MouseCursor_LeftMousePressedOutside(MouseCursor mouseCursor)
        {
            if (control.IsActive)
                OnOuterClick(mouseCursor);
        }

        private void MouseCursor_RightButtonPressedOutside(MouseCursor mouseCursor)
        {
            if (control.IsActive)
                OnOuterClick(mouseCursor);
        }

        private void PlayerKeyboard_KeysReleased(Keys[] keys)
        {
            OnKeyReleased(keys);
        }

        private void PlayerKeyboard_KeysPressed(Keys[] keys)
        {
            OnKeyPressed(keys);
        }

        private void MouseCursor_MouseMoved(MouseCursor mouseCursor)
        {
            OnMouseMoved(mouseCursor);
        }

        private void MouseCursor_RightButtonReleased(MouseCursor mouseCursor)
        {
            OnMouseRelease(mouseCursor);
        }

        private void MouseCursor_LeftMouseReleased(MouseCursor mouseCursor)
        {
            OnMouseRelease(mouseCursor);
        }

        private void MouseCursor_RightButtonPressed(MouseCursor mouseCursor)
        {
            OnMousePress(mouseCursor);
        }

        private void MouseCursor_LeftMousePressed(MouseCursor mouseCursor)
        {
            OnMousePress(mouseCursor);
        }
        
        #endregion
    }
}
